package model;


import java.util.ArrayList;
import java.util.HashMap;
import util.IniParameters;


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author ilstxfe
 */
public abstract class Tasks {
    protected int totalLevels=IniParameters.numberOfFloors;
    protected HashMap<String,ArrayList<TaskElement>> upMap;   //store up requests for each level
    protected HashMap<String,ArrayList<TaskElement>> downMap; //store down requests for each level
    protected ArrayList<TaskElement> state;      //store the tasks that represent current people in elevator
    protected double totalWaitingTime = 0;    
    protected int taskNumber = 0;
    
    //protected boolean isLeft;          
    protected boolean isLoading;       //used in doingTasks; true for loading persons 
    protected boolean isUnloading;	 //used in finishTasks; true for unloading persons
    protected boolean isFull = false;  //used in doingTasks; true when elevator is full
       
   

    public Tasks(){
        //this.isLeft = isLeft;
        upMap = new HashMap<String,ArrayList<TaskElement>>(totalLevels);
        downMap = new HashMap<String,ArrayList<TaskElement>>(totalLevels);
        state = new ArrayList<TaskElement>();
    }
    
    //return true to indicate waiting is needed
    //direction :1 for up, 0 for stable, -1 for down
    public abstract boolean doingTask(int currentLevel, int direction);        
    
    //return true for waiting when persons left
    public abstract boolean finishTask(int currentLevel);
    
    public abstract void addTask(TaskElement element);  
    
    
    
    public double getAverageWaitingTime(){
    	if(taskNumber == 0)
    		return 0;
    	else{
    		return (int)totalWaitingTime/taskNumber;
    	}    	
    }
    
    public void addToTotalWaitingTime(double currentWaitingTime){
    	totalWaitingTime += currentWaitingTime;    	
    }    
    
    public boolean isElevatorEmpty(){
    	if(state.size() == 0)
    		return true;
    	else
    		return false;
    }
    
    //return  1 or -1 or 0; 
    //-1 indicates elevator should turn to move down, 0 indicated stable, 1 indicate move up
    //This method is called when elevator is moving up
    public int UpMovingCheck(int currentLevel){  
    	boolean upMostIndex = false;
    	boolean lowLevelTaskIndex = false;   //indicate if there are tasks in lower levels
    	boolean currentLevelDownIndex = false;
    	int index;
    	
    	if(!isElevatorEmpty())
    		return 1;
    	
    	for(int i = currentLevel + 1; i < totalLevels && !upMostIndex; i++){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			upMostIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			upMostIndex = true;
    	}
    	
    	if(upMap.containsKey(String.valueOf(currentLevel)) && !upMap.get(String.valueOf(currentLevel)).isEmpty()){
    		upMostIndex = true;    		
    	}
    	
    	if(downMap.containsKey(String.valueOf(currentLevel)) && !downMap.get(String.valueOf(currentLevel)).isEmpty()){
    		currentLevelDownIndex = true;
    	}
    	
    	for(int i = currentLevel - 1; i >= 0 && !lowLevelTaskIndex; i--){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			lowLevelTaskIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			lowLevelTaskIndex = true;
    	}
    	
    	if(upMostIndex)
    		index = 1;
    	else if(!upMostIndex && !lowLevelTaskIndex && !currentLevelDownIndex)
    		index = 0;    	
    	else //(!upMostIndex && lowLevelTaskIndex)
    		index = -1;   	
    	
    	return index;
    }
    
    //return  1 or -1 or 0; 
    //-1 indicates elevator should turn to move down, 0 indicated stable, 1 indicate move up
    //This method is called when elevator is moving down
    public int downMovingCheck(int currentLevel){
    	boolean downMostIndex = false;
    	boolean upLevelTaskIndex = false;   //indicate if there are tasks in upper levels
    	boolean currentLevelUpIndex = false;
    	int index;
    	
    	if(!isElevatorEmpty())
    		return -1;
    	
    	for(int i = currentLevel - 1; i >= 0 && !downMostIndex; i--){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			downMostIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			downMostIndex = true;
    	}
    	
    	if(downMap.containsKey(String.valueOf(currentLevel)) && !downMap.get(String.valueOf(currentLevel)).isEmpty()){
    		downMostIndex = true;    		
    	}
    	
    	if(upMap.containsKey(String.valueOf(currentLevel)) && !upMap.get(String.valueOf(currentLevel)).isEmpty()){
    		currentLevelUpIndex = true;
    	}
    	    	
    	for(int i = currentLevel + 1; i < totalLevels && !upLevelTaskIndex; i++){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			upLevelTaskIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			upLevelTaskIndex = true;
    	}
    	
    	if(downMostIndex)
    		index = -1;
    	else if(!downMostIndex && !upLevelTaskIndex && !currentLevelUpIndex)
    		index = 0;
    	else //(!downMostIndex && upLevelTaskIndex)
    		index = 1;
    	
    	return index;
    }
    
    //return  1 or -1 or 0; 
    //-1 indicates elevator should turn to move down, 0 indicated stable, 1 indicate move up
    //This method is called when elevator is stable
    public int stableCheck(int currentLevel){
    	boolean highLevel = existHigherLevelRequest(currentLevel);
    	boolean lowLevel = existLowerLevelRequest(currentLevel);    	
    	int index;
    	
    	if(upMap.containsKey(String.valueOf(currentLevel)) && !upMap.get(String.valueOf(currentLevel)).isEmpty())
			highLevel = true;
		if(downMap.containsKey(String.valueOf(currentLevel)) && !downMap.get(String.valueOf(currentLevel)).isEmpty())
			lowLevel = true;
    	
    	if(!highLevel && !lowLevel)
    		index = 0;
    	else if(!highLevel && lowLevel)
    		index = -1;
    	else  // (highLevel && !lowLevel) && (highLevel && lowLevel)
    		index = 1;
    	
    	return index;   		
    }

    //check if there are requests in higher levels; true for exist
    private boolean existHigherLevelRequest(int currentLevel){
    	boolean higherLevelRequestIndex = false;
    	
    	for(int i = currentLevel + 1; i < totalLevels && !higherLevelRequestIndex; i++){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			higherLevelRequestIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			higherLevelRequestIndex = true;
    	}
    	
    	return higherLevelRequestIndex;
    }
    
    //check if there are requests in lower levels; true for exist
    private boolean existLowerLevelRequest(int currentLevel){
    	boolean lowerLevelRequestIndex = false;
    	
    	for(int i = currentLevel - 1; i >= 0 && !lowerLevelRequestIndex; i--){
    		if(upMap.containsKey(String.valueOf(i)) && !upMap.get(String.valueOf(i)).isEmpty())
    			lowerLevelRequestIndex = true;
    		if(downMap.containsKey(String.valueOf(i)) && !downMap.get(String.valueOf(i)).isEmpty())
    			lowerLevelRequestIndex = true;
    	}
    	
    	return lowerLevelRequestIndex;
    }
/*
    public boolean isUpMapEmpty(){
    	boolean index = true;
    	for(int i = 0; i < upMap.size() && index; i++){
    		if(!upMap.get(String.valueOf(i)).isEmpty())
    			index = false;
    	}
    	return index;
    }
    
    public boolean isDownMapEmpty(){
    	boolean index = true;
    	for(int i = 0; i < downMap.size() && index; i++){
    		if(!downMap.get(String.valueOf(i)).isEmpty())
    			index = false;
    	}
    	return index;
    }
*/ 
/*
    public int numberOfUp(int currentLevel){
    	ArrayList<TaskElement> temp = upMap.get(String.valueOf(currentLevel));
    	return temp.size();
    }
    
    public int numberOfDown(int currentLevel){
    	ArrayList<TaskElement> temp = downMap.get(String.valueOf(currentLevel));
    	return temp.size();
    }
*/
    
    public HashMap<String,ArrayList<TaskElement>> getUpMap(){
    	return upMap;
    }
    
    public HashMap<String,ArrayList<TaskElement>> getDownMap(){
    	return downMap;
    }
    
    public ArrayList<TaskElement> getState(){
    	return state;
    }
    
    public ArrayList<TaskElement> getTasksOfFloor(int floor)
    {
    	ArrayList<TaskElement> result = new ArrayList<TaskElement>();
    	
    	if(upMap.containsKey(String.valueOf(floor))){
    		Object[] temp1 = upMap.get(String.valueOf(floor)).toArray();
    		//result.addAll(upMap.get(String.valueOf(floor)));
    		for(Object e: temp1){
    			if(e instanceof TaskElement)
    				result.add((TaskElement)e);
    		}
    	}
    		
    	if(downMap.containsKey(String.valueOf(floor))){
    		//result.addAll(downMap.get(String.valueOf(floor)));
    		Object[] temp2 = downMap.get(String.valueOf(floor)).toArray();			
			for(Object e: temp2){
				if(e instanceof TaskElement)
    				result.add((TaskElement)e);
			}
		}
    	    	
    	return result;
    }
}
